package com.solo.system.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.solo.common.core.base.service.impl.BasicServiceImpl;
import com.solo.common.core.utils.collection.CollUtils;
import com.solo.satoken.utils.LoginHelper;
import com.solo.system.api.consts.notice.NoticeStatus;
import com.solo.system.api.entity.SysNotice;
import com.solo.system.api.entity.SysNoticeUser;
import com.solo.system.mapper.SysNoticeMapper;
import com.solo.system.model.notice.SysNoticeConvert;
import com.solo.system.model.notice.SysNoticeUserConvert;
import com.solo.system.model.notice.req.NoticeCreateReq;
import com.solo.system.model.notice.req.NoticeUpdateReq;
import com.solo.system.service.SysNoticeService;
import com.solo.system.service.SysNoticeUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;

import static com.solo.common.core.utils.ServiceExceptionUtil.exception;
import static com.solo.system.api.consts.SystemCode.*;

/**
 * 通知公告 Service实现类
 * @author 十一
 * @since 2024-12-02 17:27
 * 人生若只如初见，何事秋风悲画扇
 **/
@Service
@RequiredArgsConstructor
public class SysNoticeServiceImpl extends BasicServiceImpl<SysNoticeMapper, SysNotice> implements SysNoticeService {

    private final SysNoticeUserService sysNoticeUserService;
    
    @Override
    @Transactional
    public boolean create(NoticeCreateReq req) {
        SysNotice entity = SysNoticeConvert.INSTANCE.convert(req);
        // 验证是否是发布按钮
        validateIsPublish(entity);
        // 保存数据
        boolean result = save(entity);
        // 如果保存数据成功 && 接收人不为空 则批量插入接收人
        if (result && CollUtils.isNotEmpty(req.getReceivers())) {
            List<SysNoticeUser> createNoticeUserList = SysNoticeUserConvert.INSTANCE.convert(req.getReceivers(), entity.getNoticeId());
            sysNoticeUserService.saveBatch(createNoticeUserList);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(NoticeUpdateReq req) {
        SysNotice entity = SysNoticeConvert.INSTANCE.convert(req);
        // 验证通知公告是否存在
        SysNotice notice = validateExists(entity.getNoticeId());
        // 验证通知公告是否可以发布（发布状态数据不可编辑）
        validateIsCouldPublish(notice.getStatus());
        // 验证是否是发布按钮
        validateIsPublish(entity);
        // 更新数据
        boolean result = updateById(entity);
        // 如果更新数据成功 则批量插入接收人
        if (result) {
            sysNoticeUserService.saveBatch(req.getReceivers(), entity.getNoticeId());
        }
        return result;
    }

    @Override
    public boolean publish(Long noticeId) {
        SysNotice notice = getById(noticeId);
        // 验证通知公告是否可以发布（发布状态数据不可重新发布）
        validateIsCouldPublish(notice.getStatus());
        notice.setStatus(NoticeStatus.PUBLISH);
        notice.setSendBy(String.valueOf(LoginHelper.getUserId()));
        notice.setSendTime(LocalDateTime.now());
        return updateById(notice);
    }

    @Override
    public boolean quash(Long noticeId) {
        // 验证通知公告是否存在
        SysNotice notice = validateExists(noticeId);
        // 验证通知公告是否可以撤销
        validateIsCouldQuash(notice.getSendTime(), notice.getStatus());
        notice.setStatus(NoticeStatus.QUASH);
        notice.setRevokeBy(String.valueOf(LoginHelper.getUserId()));
        notice.setRevokeTime(LocalDateTime.now());
        return updateById(notice);
    }
    
    /**
     * 是否是发布按钮
     * @param notice 通知
     */
    void validateIsPublish(SysNotice notice) {
        // 如果是发布按钮，则设置发布时间、发布人、发布状态。如果是草稿则不需要设置任何值。
        if (notice.getStatus().equals(NoticeStatus.PUBLISH)) {
            notice.setStatus(NoticeStatus.PUBLISH);
            notice.setSendBy(String.valueOf(LoginHelper.getUserId()));
            notice.setSendTime(LocalDateTime.now());
        }
    }

    /**
     * 验证通知公告是否存在
     * @param noticeId 通知id
     * @return {@link SysNotice }
     */
    SysNotice validateExists(Long noticeId) {
        if (noticeId == null) {
            throw exception(NOTICE_NOT_FOUND);
        }
        SysNotice entity = mapper.selectOneById(noticeId);
        if (entity == null) {
            throw exception(NOTICE_NOT_FOUND);
        }
        return entity;
    }

    /**
     * 验证通知公告是否可以发布（发布状态的数据，不可编辑）
     * @param status 当前状态
     */
    void validateIsCouldPublish(NoticeStatus status) {
        if (status.equals(NoticeStatus.PUBLISH)) {
            throw exception(NOTICE_STATUS_NOT_ACTIONABLE);
        }
    }
    
    /**
     * 验证通知公告是否可以撤销
     * @param publishTime 发布时间
     */
    void validateIsCouldQuash(LocalDateTime publishTime, NoticeStatus status) {
        // 只有已发布的通知公告才可以撤销
        if (!status.equals(NoticeStatus.PUBLISH)) {
            throw exception(NOTICE_STATUS_IRREVOCABLE);
        }
        // 发布时间超过十分钟不可撤销
        long between = LocalDateTimeUtil.between(publishTime, LocalDateTime.now(), ChronoUnit.MINUTES);
        if (between > 10) {
            throw exception(NOTICE_TIMEOUT_IRREVOCABLE);
        }
    }

}
